import type { ComputedRef, Ref } from 'vue';
import { computed, ref, unref, watch } from 'vue';
import { cloneDeep, isArray, isFunction } from 'lodash-es';
import type { RowData } from 'naive-ui/es/data-table/src/interface';

import type { BasicTableColumn } from '../types/table';

import type { BasicTableProps } from '@/components/table/src/props';
import { renderTableField } from '@/components/table/src/hooks/render';
import TableFieldType from '@/components/table/src/types/field-type';
import TableAction from '@/components/table/src/components/table-action.vue';
import { computeOperationsColumnWidth } from '@/components/table/src/helpers/action-buttons';

export function useColumns(propsRef: ComputedRef<BasicTableProps>) {
  const columnsRef = ref(unref(propsRef).columns) as unknown as Ref<BasicTableColumn[]>;
  let cacheColumns = unref(propsRef).columns;

  const alignCenterColumn = [TableFieldType.BOOLEAN, TableFieldType.TAG, TableFieldType.ICON];

  // 从props获取
  const getColumnsRef = computed(() => {
    const columns = cloneDeep(unref(columnsRef));
    handleActionColumn(propsRef, columns);

    // 排序
    const resultColumns = columns.map((item, index) => {
      return {
        ...item,
        sort: item.sort ?? index,
      };
    }).sort((a, b) => a.sort - b.sort);

    return !columns ? [] : resultColumns;
  });

  // 页面展示用
  const getPageColumns = computed(() => {
    const pageColumns = unref(getColumnsRef);
    const columns = cloneDeep(pageColumns);

    return columns
      .filter(column => column.display ?? true)
      .map(column => {
        const align = alignCenterColumn.includes(column.fieldType) ? 'center' : column.align;
        return {
          ...column,
          align,
          render: isFunction(column.render)
            ? (rowData: RowData, _: any) => {
                const value = rowData[column.key] ?? column.defaultValue;
                return column.render?.call(undefined, value, rowData);
              }
            : renderTableField(column),
        };
      });
  });

  watch(
    () => unref(propsRef).columns,
    columns => {
      columnsRef.value = columns;
      cacheColumns = columns;
    },
  );

  /**
   * 处理操作列
   * @param propsRef
   * @param columns
   */
  function handleActionColumn(propsRef: ComputedRef<BasicTableProps>, columns: BasicTableColumn[]) {
    const { actionButtons, maxVisibleActionButtons } = unref(propsRef);

    if (!actionButtons || actionButtons.length === 0 || !maxVisibleActionButtons) {
      return;
    }
    columns.push({
      title: '操作',
      key: 'action',
      align: 'center',
      fixed: 'right',
      width: computeOperationsColumnWidth(actionButtons, maxVisibleActionButtons),
      render: (_value: any, row: Recordable) => {
        return h(TableAction, { row, actionButtons, maxVisibleActionButtons });
      },
    } as any);
  }

  function setColumns(columnKeys: string[]) {
    if (!isArray(columnKeys)) {
      return;
    }
    if (!columnKeys.length) {
      columnsRef.value = [];
    }

    const newColumns: BasicTableColumn[] = [];
    columnKeys.forEach(key => {
      const column = cacheColumns.find(item => item.key === key);
      if (column) {
        newColumns.push(column);
      }
    });

    columnsRef.value = newColumns;
  }

  function setSelection(select: boolean) {
    if (select) {
      if (columnsRef.value[0].key === 'selection') {
        return;
      }
      columnsRef.value.unshift({ type: 'selection', key: 'selection' } as any);
    } else if (columnsRef.value[0].key === 'selection') {
      columnsRef.value.splice(0, 1);
    }
  }

  function getColumns(): BasicTableColumn[] {
    const columns = toRaw(unref(getColumnsRef));
    return columns
      .filter(item => item.key !== 'selection')
      .map(item => {
        return { ...item, title: item.title, key: item.key, fixed: item.fixed || undefined };
      });
  }

  function getCacheColumns(onlyKey: boolean): BasicTableColumn[] | string[] {
    return onlyKey ? cacheColumns.map(item => item.key as string) : cacheColumns;
  }

  /**
   * 更新原始数据单个字段
   * @param key
   * @param value
   */
  function setCacheColumnsField(key: string | undefined, value: Partial<BasicTableColumn>) {
    if (!key || !value) {
      return;
    }
    cacheColumns.forEach(item => {
      if (item.key === key) {
        Object.assign(item, value);
      }
    });
  }

  return {
    getColumns,
    setColumns,
    getPageColumns,
    getCacheColumns,
    setCacheColumnsField,
    setSelection,
  };
}
